#include "../Typelists/TypeList.h"
/**
 * Automate the Brute-Force dispatcher, using template recursive instantiation
 */
template<class Executor,class BaseLhs,class TypesLhs,
	class BaseRhs = BaseLhs, class TypesRhs = TypesLhs, typename ResultType = void>
class StaticDispatcher
{
	typedef typename TypesLhs::Head Head;
	typedef typename TypesLhs::Tail Tail;
public:
	static ResultType Go(BaseLhs& lhs, BaseRhs& rhs, Executor exec);
	template<class SomeLhs>
	static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs, Executor exec);
};

/**
 * specialized class template with Go member function
 */
template<class Executor,class BaseLhs,class BaseRhs, class TypesRhs, 
	typename ResultType>
class StaticDispatcher<Executor,BaseLhs,NullType,BaseRhs,TypesRhs,ResultType>
{
public:
	static ResultType Go(BaseLhs& lhs, BaseRhs& rhs, Executor exec)
	{
		exec.OnError(lhs,rhs);
	}
};

/**
 * specialized class template with DispatcheRhs member function
 */
template<class Executor,class BaseLhs,class TypesLhs,
	class BaseRhs, typename ResultType>
class StaticDispatcher<Executor,BaseLhs,TypesLhs,BaseRhs,NullType,ResultType>
{
public:
	static void DispatchRhs(BaseLhs& lhs, BaseRhs& rhs, Executor exec)
	{
		exec.OnError(lhs,rhs);
	}
};

template<class Executor,class BaseLhs,class TypesLhs,
	class BaseRhs, class TypesRhs, typename ResultType>
ResultType StaticDispatcher<Executor,BaseLhs,TypesLhs,BaseRhs,TypesRhs,ResultType>
	::Go(BaseLhs& lhs, BaseRhs& rhs, Executor exec)
{
	if(Head* p1 = dynamic_cast<Head*>(&lhs))
		return StaticDispatcher<Executor,BaseLhs,TypesLhs,BaseRhs,TypesRhs,ResultType>
		::DispatchRhs(*p1,rhs,exec);
	else
		return StaticDispatcher<Executor,BaseLhs,Tail,BaseRhs,TypesRhs,ResultType>
		::Go(lhs,rhs,exec);
}

template<class Executor,class BaseLhs,class TypesLhs,
	class BaseRhs, class TypesRhs, typename ResultType>
template<class SomeLhs>
ResultType StaticDispatcher<Executor,BaseLhs,TypesLhs,BaseRhs,TypesRhs,ResultType>
	::DispatchRhs(SomeLhs& lhs, BaseRhs& rhs, Executor exec)
{
	typedef typename TypesRhs::Head Head;
	typedef typename TypesRhs::Tail Tail;
	if (Head* p2 = dynamic_cast<Head*>(&rhs))
		return exec.Fire(lhs,*p2);
	else
		return StaticDispatcher<Executor,SomeLhs,TypesLhs,BaseRhs,Tail,ResultType>
			::DispatchRhs(lhs,rhs,exec);
}
